"""
利用Mixins扩展类功能

问题：
    你有很多有用的方法，想使用它们来扩展其他类的功能。
    但是这些类并没有任何继承的关系。
    因此你不能简单的将这些方法放入一个基类，然后被其他类继承。
解决方案：
    通常当你想自定义类的时候会碰上这些问题。
    可能是某个库提供了一些基础类， 你可以利用它们来构造你自己的类。
"""

from collections import defaultdict


class LoggedMappingMixin:
    # 混入类都没有实例变量，因为直接实例化混入类没有任何意义
    __slots__ = ()

    def __getitem__(self, key):
        print("Getting", key)
        return super().__getitem__(key)

    def __setitem__(self, key, value):
        print("Setting {} = {!r}".format(key, value))
        return super().__setitem__(key, value)

    def __delitem__(self, key):
        print("Deleting", key)
        return super().__delitem__(key)


class SetOnceMappingMixin:
    __slots__ = ()

    def __setitem__(self, key, value):
        if key in self:
            raise KeyError(str(key) + " already set")

        return super().__setitem__(key, value)


class StringKeyMappingMixin:
    __slots__ = ()

    def __setitem__(self, key, value):
        if not isinstance(key, str):
            raise TypeError("keys must be strings")

        return super().__setitem__(key, value)


class LoggedDict(LoggedMappingMixin, dict):
    pass


class SetOnceDefaultDict(SetOnceMappingMixin, defaultdict):
    pass


def use_mixin():
    logged_dict = LoggedDict()
    logged_dict["name"] = "Kevin"
    print(logged_dict["name"])
    del logged_dict["name"]

    set_once_dict = SetOnceDefaultDict(list)
    set_once_dict["name"].append("Kevin")
    set_once_dict["name"].append("葛小伦")
    print(set_once_dict)

    # 输出结果：
    """
    Setting name = 'Kevin'
    Getting name
    Kevin
    Deleting name
    defaultdict(<class 'list'>, {'name': ['Kevin', '葛小伦']})
    """


if __name__ == '__main__':
    use_mixin()
